﻿using AutoEntities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace AutoMap
{
    /// <summary>
    /// 表达式映射，缓存为泛型
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TResult"></typeparam>
    public class ExpressionMapper<T, TResult> where TResult : new()
    {
        private static Func<T, TResult>? func = null;

        public static TResult Map(T entity)
        {
            if (func != null) return func(entity);
            ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "m");
            var targettype = typeof(TResult);
            List<MemberBinding> memberBindings = new();
            foreach (var property in typeof(T).GetProperties())
            {
                var memberExpression = Expression.Property(parameterExpression, property.Name);
                var targetProperty = targettype.GetProperty(property.Name);
                if (targetProperty == null) continue;
                var memberBinding = Expression.Bind(targetProperty, memberExpression);
                memberBindings.Add(memberBinding);
            }

            var resultExpression = Expression.New(typeof(TResult));
            var memberInit = Expression.MemberInit(resultExpression, memberBindings);
            var lambdaExpression = Expression.Lambda<Func<T, TResult>>(memberInit, parameterExpression);
            func = lambdaExpression.Compile();

            return func(entity);
        }
    }
}
